<!-- 修改头像的组件 -->

<!-- 显示文件列表 配合on-preview更好用 无法使用预览，因为点击事件已经被上传功能使用了 
  :before-upload="beforeAvatarUpload"
  :on-error="handleAvatarError"
-->
<template>
  <div class="component-upload-image">
    <el-upload
      class="avatar-uploader"
      ref="uploadRef"
      action="#"
      :show-file-list="true"
      list-type="picture"
      :on-preview="handlePictureCardPreview"
      :on-change="handleAvatarChange"
      :on-exceed="handleExceed"
      :auto-upload="false"
      :limit="1"
      :accept="acceptString"
      :http-request="submitUpload"
    >
      <!-- 获取当前头像 -->
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
      <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
      <!-- <template #file="{ file }">
        <div>
          <img
            v-if="isImage(file.url)"
            class="el-upload-list__item-thumbnail"
            :src="file.url"
            alt=""
          />
        </div>
      </template> -->
    </el-upload>
    <el-button class="ml-3" type="success" @click="submitUpload">
      上传
    </el-button>
    <!-- 上传提示 -->
    <div class="el-upload__tip" v-if="showTip">
      请上传
      <template v-if="fileSize">
        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
      </template>
      <template v-if="fileType">
        格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
      </template>
      的文件
    </div>

    <el-dialog v-model="dialogVisible" title="预览" width="600px">
      <img
        :src="dialogImageUrl"
        alt="Preview Image"
        style="height: 95%; width: 95%"
      />
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import {
  ref,
  computed,
  useAttrs,
  inject,
  onMounted,
  getCurrentInstance,
  defineEmits,
} from "vue";
import { ElMessage } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import { genFileId } from "element-plus";
import type { UploadInstance, UploadProps, UploadRawFile } from "element-plus";
import { useTokenStore } from "@/store/token";
import { watch, watchEffect } from "vue";

const props = defineProps({
  // 原头像url
  imageUrl: String,
  modelValue: [String, Object, Array],
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
  // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => ["png", "jpg", "jpeg"],
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true,
  },
});
const { proxy } = getCurrentInstance();
const tokenStore = useTokenStore();
const uploadRef = ref<UploadInstance>();
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const emit = defineEmits(["file"]);
const imageUrl = ref("");
// 注入对象
const userInfo = inject("userInfo");

// const attrs = useAttrs();
// console.log("透传的属性uploadAvatar:", attrs);
// 设置headers
const headers = {
  satoken: tokenStore.token,
};

interface DataForm {
  name: string;
  file: UploadRawFile | null; // 确保 file 字段能够接受 UploadRawFile 类型的对象
}
const dataForm = ref<DataForm>({
  name: "",
  file: null,
});

//  给父组件传过来的值赋值给imageUrl
onMounted(() => {
  getImg();
});

// 文件类型
const acceptString = computed(() => {
  // 1. 确保每个文件类型前有 '.' 并过滤空值
  const validTypes = props.fileType
    .map((type) => `.${type.trim()}`)
    .filter((type) => type.length > 1 && !type.includes(" "));

  // 2. 使用逗号连接（自动过滤空字符串）
  return validTypes.join(",");
});
//  给 imageUrl 赋值
const getImg = () => {
  imageUrl.value = userInfo.value.avatarurl;
};

// 监听imageUrl的值是否为空，为空则重新获取
watch(
  () => imageUrl.value,
  (newImageUrl) => {
    if (newImageUrl == "") {
      setTimeout(() => {
        getImg();
      }, 500);
    }
  }
);

// 获取是否显示提示信息
const showTip = computed(
  () => props.isShowTip && (props.fileType || props.fileSize)
);

// 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
const handleAvatarChange: UploadProps["onChange"] = (
  uploadFile,
  uploadFiles
) => {
  // 判断文件类型
  let isImg = false;
  let rawFile = uploadFile.raw!;
  if (props.fileType.length) {
    let fileExtension = "";
    if (rawFile.name.lastIndexOf(".") > -1) {
      fileExtension = rawFile.name.slice(rawFile.name.lastIndexOf(".") + 1);
    }
    isImg = props.fileType.some((type) => {
      // console.log("type:", type);
      if (fileExtension && fileExtension == type) {
        return true;
      }
    });
    // console.log("fileExtension:", fileExtension);
    // console.log("Is image:", isImg);
  }
  if (!isImg) {
    ElMessage.error(
      `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
    );
    uploadRef.value!.clearFiles();
  } else {
    console.log("uploadFile", uploadFile);

    imageUrl.value = URL.createObjectURL(uploadFile.raw!);
    dataForm.value.name = uploadFile.raw!.name;
    dataForm.value.file = uploadFile.raw!;
  }
};
//  文件超出个数限制时的钩子（覆盖上传）
const handleExceed: UploadProps["onExceed"] = (files) => {
  uploadRef.value!.clearFiles();
  const file = files[0] as UploadRawFile;
  file.uid = genFileId();
  uploadRef.value!.handleStart(file);
};
// 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
const beforeAvatarUpload: UploadProps["beforeUpload"] = (rawFile) => {
  // 判断文件后缀
  let isImg = false;
  if (props.fileType.length) {
    let fileExtension = "";
    if (rawFile.name.lastIndexOf(".") > -1) {
      fileExtension = rawFile.name.slice(rawFile.name.lastIndexOf(".") + 1);
    }
    isImg = props.fileType.some((type) => {
      if (rawFile.type.indexOf(type) > -1) return true;
      if (fileExtension && fileExtension.indexOf(type) > -1) return true;
      return false;
    });
  } else {
    isImg = rawFile.type.indexOf("image") > -1;
  }
  if (!isImg) {
    ElMessage.error(
      `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
    );
    return false;
  }

  // if (rawFile.type !== "image/jpeg" && rawFile.type !== "image/png") {
  //   ElMessage.error("文件格式不正确!");
  //   return false;
  // }

  if (rawFile.size / 1024 / 1024 > 5) {
    ElMessage.error("文件大小超过5M!");
    return false;
  }
  return true;
};
// 预览
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url!;
  dialogVisible.value = true;
};

// 文件上传失败的回调
const handleAvatarError: UploadProps["onError"] = (error, uploadFile) => {
  ElMessage.error("上传失败!");
};

// 文件提交
const submitUpload: UploadProps["httpRequest"] = async (file) => {
  console.log("uploadRef", dataForm.value);
  let ImgFile = dataForm.value.file;

  // 检查文件是否有效
  if (!(ImgFile instanceof File)) {
    ElMessage.info("请点击图片上传!");
    // console.error("无效的文件,点击图片上传!");
    return;
  }
  ElMessage.success("上传成功!");
  // 将文件信息传给父组件,加上文件名
  emit("file", dataForm.value);
};
// 点击Dialog之外的地方，关闭Dialog后清空数据
const clearFileListByDialog = () => {
  uploadRef.value!.clearFiles();
  imageUrl.value = "";
};

// 上传文件后的清空
const clearFileList = () => {
  uploadRef.value!.clearFiles();
  imageUrl.value = "";
};

// 将清除文件列表的方法暴露给父组件
defineExpose({
  clearFileList,
  clearFileListByDialog,
});

// 判断文件是否是png(从文件本身判断，不是看后缀)
async function isPNG(file: File) {
  // 提取前8个字节
  const arraybuffer = await file.slice(0, 8).arrayBuffer();

  // PNG 的前8字节16进制表示
  const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
  // const signature = [137, 80, 78, 71, 13, 10, 26, 10]

  // 转为 8位无符号整数数组 方便对比
  // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
  const source = new Uint8Array(arraybuffer);

  // 逐个字节对比
  for (let i = 0; i < signature.length; i++) {
    if (source[i] !== signature[i]) {
      return false;
    }
  }
  return true;
}
</script>

<style scoped lang="scss">
.avatar-uploader .avatar {
  width: 100%;
  height: 100%;
  display: block;
}
</style>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>
